package cn.zxh.improvement.common.core.context;

import cn.zxh.improvement.common.core.function.SupplierWithException;
import cn.zxh.improvement.common.core.utils.Reflections;
import io.vavr.control.Option;

/**
 * 应用上下文
 *
 * @author zxh
 * @since 2023-4-28 16:54:40
 */
public interface Context {

    /**
     * 获取应用上下文实例
     *
     * @return 上下文实例
     */
    static Context getInstance() {
        return ContextRegister.context;
    }

    /**
     * 根本name获取 bean，没有就使用默认值
     * ·
     *
     * @param <T>  bean类型
     * @param name bean名字
     * @param def  默认值
     * @return bean实例
     */
    default <T> T getBean(String name, T def) {
        return this.<T>getBean(name).getOrElse(def);
    }

    /**
     * 根据名字获取bean，并强制转类型
     *
     * @param <T>  bean类型
     * @param name bean名字
     * @param cls  beanClass类型
     * @return 包装bean
     */
    default <T> Option<T> getBean(String name, Class<T> cls) {
        return this.<T>getBean(name).filter(bean -> Reflections.requireInstanceOf(bean, cls));
    }

    /**
     * 根据名字获取bean
     *
     * @param <T>  bean类型
     * @param name bean名字
     * @return 包装bean
     */
    <T> Option<T> getBean(String name);

    /**
     * 根据class类型获取bean
     *
     * @param <T> bean类型
     * @param cls bean名称
     * @return 包装bean
     */
    default <T> Option<T> getBean(Class<T> cls) {
        return getBean(cls.getName());
    }

    /**
     * 根本class类型获取 bean，没有就使用默认值
     *
     * @param <T> bean类型
     * @param cls beanClass
     * @param def 默认值
     * @return bean实例
     */
    default <T> T getBean(Class<T> cls, T def) {
        return this.getBean(cls).getOrElse(def);
    }

    /**
     * 根本class类型获取 bean，没有就从提供商函数获取
     *
     * @param <T> bean类型
     * @param cls beanClass
     * @param def 默认值提供商
     * @return bean实例
     */
    default <T> T getBean(Class<T> cls, SupplierWithException<T> def) {
        return this.getBean(cls).getOrElse(def);
    }

    /**
     * 设置bean
     *
     * @param <T>  bean类型
     * @param name bean名称
     * @param bean bean实例
     * @return bean实例
     */
    <T> T setBean(String name, T bean);

    /**
     * 设置bean
     *
     * @param <T>  bean类型
     * @param cls  beanClass
     * @param bean bean实例
     * @return bean实例
     */
    default <T> T setBean(Class<T> cls, T bean) {
        return setBean(cls.getName(), bean);
    }

}
